/*
 * action_utils.c
 *
 * This file contains the source code for the default event handlers, as well as
 * helper functions for creating events and actions.
 */

#include <stdlib.h>
#include <controller/timer.h>
#include <map/map_handler.h>
#include "npc.h"
#include "action_utils.h"
#include "event_utils.h"
#include <agent/go_unit.h>

/*
 * Moves the unit described in the given event by the given x/y values described
 * in the given event.
 */
event * move_unit( action *a ) {
    unit *target;
    move_event *data;
    event *e;
    e = (event*)malloc(sizeof(event));
    data = (move_event*)(a->info);
    e->type = a->type;
    target = data->mover;
    if( data->delta_x < 0 && target->x < data->delta_x * -1 ) {
        data->delta_x = target->x * -1;
    }
    if( data->delta_y < 0 && target->y < data->delta_y * -1 ) {
        data->delta_y = target->y * -1;
    }
    if( target->x > (map_get_width() * TILESIZE) - data->delta_x ) {
        data->delta_x = (map_get_width() * TILESIZE) - target->x;
    }
    if( target->y > (map_get_height() * TILESIZE) - data->delta_y ) {
        data->delta_y = (map_get_height() * TILESIZE) - target->y;
    }
    target->x += data->delta_x;
    target->y += data->delta_y;
    e->info = (void*)data;
    return e;
}

/*
 * Damages the unit described in the given event by the given amount described
 * in the given event.
 */
event * damage_unit( action *a ) {
    unit *victim;
    go_stats *victim_g;
    damage_event *data;
    event *e;
    e = (event*)malloc(sizeof(event));
    int amount;
    data = (damage_event*)(a->info);
    victim = data->victim;
    amount = data->amount;
    victim_g = ((go_stats*)victim->stats);
    e->type = a->type;
    e->info = (void*)data;
    victim_g->hp -= amount;
    if( amount > victim_g->hp_max / 8 ) {
        timed_controller_add( create_bleed_action( bleed_event_t, victim,
            amount/2 ), 3 );
    }
    return e;
}

/*
 * Bleeds the unit described in the given event by the given amount described,
 * dealing damage. If the damage is high enough, will create a new bleed event
 * for less damage and queue it in the timed controller
 */
event * bleed_unit( action *a ) {
    unit *victim;
    go_stats *victim_g;
    bleed_event *data;
    event *e;
    e = (event*)malloc(sizeof(event));
    int amount;
    data = (bleed_event*)(a->info);
    victim = data->victim;
    victim_g = ((go_stats*)victim->stats);
    amount = data->amount;
    e->type = a->type;
    e->info = (void*)data;
    victim_g->hp -= amount;
    amount /= 2;
    if( amount != 0 ) {
        timed_controller_add( create_bleed_action( a->type, victim,
            amount ), 3 ); /* 3 second delay */
    }
    return e;
}

/*
 * Causes the first unit described to attack the second, dealing the given
 * amount of damage.
 */
event * attack_unit( action *a ) {
    unit *attacker;
    unit *victim;
    go_stats *victim_g;
    attack_event *data;
    event *e;
    int amount;
    e = (event*)malloc(sizeof(event));
    data = (attack_event*)(a->info);
    attacker = data->attacker;
    victim = data->victim;
    victim_g = ((go_stats*)victim->stats);
    amount = data->amount;
    e->type = a->type;
    e->info = (void*)data;
    victim_g->hp -= amount;
    if( amount > victim_g->hp_max / 8 ) {
        timed_controller_add( create_bleed_action( bleed_event_t, victim,
            amount/2 ), 3 );
    }
    return e;
}

/* Helper functions */

/*
 * Creates a new move action, removing the need to create an event directly.
 */
action* create_move_action( event_t type, unit *u, long x, long y ) {
    action *a;
    move_event *data;
    a = (action*)malloc(sizeof(action));
    data = (move_event*)malloc(sizeof(move_event));
    data->delta_x = x;
    data->delta_y = y;
    data->mover = u;
    a->type = type;
    a->info = data;
    return a;
}

/*
 * Creates a new damage action, removing the need to create an event directly.
 */
action* create_damage_action( event_t type, unit *u, int amount ) {
    action *a;
    damage_event *data;
    a = (action*)malloc(sizeof(action));
    data = (damage_event*)malloc(sizeof(damage_event));
    data->amount = amount;
    data->victim = u;
    a->type = type;
    a->info = data;
    return a;
}

/*
 * Creates a new bleed action, removing the need to create an event directly.
 */
action* create_bleed_action( event_t type, unit *u, int amount ) {
    action *a;
    bleed_event *data;
    a = (action*)malloc(sizeof(action));
    data = (bleed_event*)malloc(sizeof(bleed_event));
    data->amount = amount;
    data->victim = u;
    a->type = type;
    a->info = data;
    return a;
}

/*
 * Creates a new attack action, removing the need to create an event directly.
 */
action* create_attack_action( event_t type, unit *attacker, unit *victim, int amount ) {
    action *a;
    attack_event *data;
    a = (action*)malloc(sizeof(action));
    data = (attack_event*)malloc(sizeof(attack_event));
    data->attacker = attacker;
    data->victim = victim;
    data->amount = amount;
    a->type = type;
    a->info = data;
    return a;
}
